
var fs = require("fs")
var child_process = require('child_process')
var request = require('request')
var path = require('path')



if (typeof JSON !== 'object') {
    JSON = {};
}

(function () {
    'use strict';
    
    var rx_one = /^[\],:{}\s]*$/,
        rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
        rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
        rx_four = /(?:^|:|,)(?:\s*\[)+/g,
        rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 
            ? '0' + n 
            : n;
    }
    
    function this_value() {
        return this.valueOf();
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function () {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear() + '-' +
                        f(this.getUTCMonth() + 1) + '-' +
                        f(this.getUTCDate()) + 'T' +
                        f(this.getUTCHours()) + ':' +
                        f(this.getUTCMinutes()) + ':' +
                        f(this.getUTCSeconds()) + 'Z'
                : null;
        };

        Boolean.prototype.toJSON = this_value;
        Number.prototype.toJSON = this_value;
        String.prototype.toJSON = this_value;
    }

    var gap,
        indent,
        meta,
        rep;


    function quote(string) {

        rx_escapable.lastIndex = 0;
        return rx_escapable.test(string) 
            ? '"' + string.replace(rx_escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string'
                    ? c
                    : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' 
            : '"' + string + '"';
    }


    function str(key, holder) {

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }


        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':
            return isFinite(value) 
                ? String(value) 
                : 'null';

        case 'boolean':
        case 'null':

            return String(value);

        case 'object':

            if (!value) {
                return 'null';
            }

            gap += indent;
            partial = [];

            if (Object.prototype.toString.apply(value) === '[object Array]') {

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

                v = partial.length === 0
                    ? '[]'
                    : gap
                        ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
                        : '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (
                                gap 
                                    ? ': ' 
                                    : ':'
                            ) + v);
                        }
                    }
                }
            } else {

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (
                                gap 
                                    ? ': ' 
                                    : ':'
                            ) + v);
                        }
                    }
                }
            }
            v = partial.length === 0
                ? '{}'
                : gap
                    ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
                    : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

    if (typeof JSON.stringify !== 'function') {
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"': '\\"',
            '\\': '\\\\'
        };
        JSON.stringify = function (value, replacer, space) {

            var i;
            gap = '';
            indent = '';
            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

            } else if (typeof space === 'string') {
                indent = space;
            }
            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

            return str('', {'': value});
        };
    }

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {
            var j;

            function walk(holder, key) {

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

            text = String(text);
            rx_dangerous.lastIndex = 0;
            if (rx_dangerous.test(text)) {
                text = text.replace(rx_dangerous, function (a) {
                    return '\\u' +
                            ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

            if (
                rx_one.test(
                    text
                        .replace(rx_two, '@')
                        .replace(rx_three, ']')
                        .replace(rx_four, '')
                )
            ) {


                j = eval('(' + text + ')');

                return typeof reviver === 'function'
                    ? walk({'': j}, '')
                    : j;
            }

            throw new SyntaxError('JSON.parse');
        };
    }
}());



//将非stringl类型递归转化为string
xToString = function(obj)
{
    if(typeof(obj) == "string")
        return obj
    else if (typeof(obj) == "boolean")
        if(obj === true)
            return 'true'
        else
            return 'false'
    else if (typeof(obj) == "number")
        return obj
    else if (typeof(obj) == "object")
    {
        if (obj instanceof Array == true)
        {
            var str = ''
            for (var i=0;i<obj.length;i++)
            {    
                if (i==0) 
                {
                    str = str + xToString(obj[i])
                }
                else
                {
                    str = str + ',' + xToString(obj[i])
                }
            }   
            //str = str + ']'
            return str
        }
        else
        {
            return JSON.stringify(obj)  //json对象转换成json对符串 
        }
    }
}


currentTime = function()
{ 
        var now   = new Date();
        var year  = now.getFullYear();       //年
        var month = now.getMonth() + 1;     //月
        var day   = now.getDate();            //日
        var hh    = now.getHours();            //时
        var mm    = now.getMinutes();          //分
        var clock = year + "-";
        if(month < 10)
            clock += "0";
        clock += month + "-";
        if(day < 10)
            clock += "0";
        clock += day + " ";
        if(hh < 10)
            clock += "0";
        clock += hh + ":";
        if (mm < 10) clock += '0'; 
        clock += mm; 
        return(clock); 
} 


clone = function(obj){  
    var o;  
    switch(typeof obj){  
    case 'undefined': break;  
    case 'string'   : o = obj + '';break;  
    case 'number'   : o = obj - 0;break;  
    case 'boolean'  : o = obj;break;  
    case 'object'   :  
        if(obj === null){  
            o = null;  
        }else{  
            if(obj instanceof Array){  
                o = [];  
                for(var i = 0, len = obj.length; i < len; i++){  
                    o.push(clone(obj[i]));  
                }  
            }else{  
                o = {};  
                for(var k in obj){  
                    o[k] = clone(obj[k]);  
                }  
            }  
        }  
        break;  
    default:          
        o = obj;break;  
    }  
    return o;     
}  


mkdirS = process.platform=='win32'?'mkdir ':'mkdir -p '
rmdirS = process.platform=='win32'?'rmdir /s /q ':'rm -rf '

chmod777S = function(path)
{
    return process.platform=='win32'?'cacls ' +  path  + ' /e /t /c /g everyone:F':'chmod -R 777 ' + path
}



///  targetPath  xxxx/xxx/xxx.png
loadRes = function(url, targetPath, onload) 
{   
    var t = path.dirname(targetPath)        

    fs.exists(targetPath, function(isExist)
    {
       if(isExist)
       {    
            try
            {
                child_process.exec(chmod777S(targetPath), function(error)
                {   
                    child_process.exec(rmdirS + targetPath, function(error)
                    {
                      load()   
                    })  
                })
            }
            catch(e)
            {
                onload?onload(e):''
                console.log('loadRes1 catch',e) 
            }
       }
       else
       {    
            try
            {
                child_process.exec(mkdirS + t, function(error)
                {
                    load()   
                })  
            }
            catch(e)
            {
                onload?onload(e):''
                console.log('loadRes2 catch',e) 
            }

       }
    })

  function load()
  {
    try
    {
        var req = request(url)
        req.pipe(fs.createWriteStream(targetPath))
        req.on('end', function() {
              onload?onload():''
              console.log('loadCreative req end',targetPath)
            })
        req.on('error', function(error) {
              onload?onload(error):''
              console.log('loadCreative req error',targetPath,error)
          })
        req.on('close', function() {
              //console.log('loadCreative req close',targetPath)
          })  
    }
    catch(e)
    {
        onload?onload(e):''
        console.log('loadRes3 catch',e) 
    }
  }
}

//groupNum 并行下载的组数  这个数量受到系统open files的数量限制
loadReses = function(urls, targetPaths, groupNum, onLoadOne, onLoadAll)
{
    var l = urls.length
    if(l==0)
    {
        onLoadOne(0)
        onLoadAll()
    }

    var urlNumPerGroup = Math.ceil(l/groupNum)
    var finishedGroupNum = 0

    groupNum = Math.ceil(l/urlNumPerGroup) 

    for(var i=0;i<groupNum;i++)
    {
        var currentIdx = urlNumPerGroup*i
        if(i == groupNum-1)
            var maxIdx = l - 1
        else
            var maxIdx = currentIdx + urlNumPerGroup - 1
       // console.log('maxIdx:',maxIdx,l,groupNum)
        fun(currentIdx, maxIdx)
    }


    //console.log('loadReses:', urls, targetPaths)
    function fun(currentIdx, maxIdx)
    {

        if(currentIdx>maxIdx) 
        {
          finishedGroupNum = finishedGroupNum + 1
          console.log('onLoadAll:',finishedGroupNum, groupNum)
          if(finishedGroupNum == groupNum)
              onLoadAll?onLoadAll():''
          return 
        }
        var url = urls[currentIdx]
        var targetPath = targetPaths[currentIdx]
       // console.log('targetPath:',targetPath, currentIdx, maxIdx,targetPaths.length)
        var onload = function()
        {
            onLoadOne?onLoadOne(currentIdx-1):''
            fun(currentIdx, maxIdx)
        }
        loadRes(url, targetPath, onload) 
        currentIdx = currentIdx + 1
    }
}

var readingNum = 0
var waitQueue = []
readFileInOrder = function(path, onRead)
{
    console.log('readFileInOrder:', path,waitQueue.length)
    var readEnableNum = 50 - readingNum

    if(readEnableNum>0)
    {   
        readingNum = readingNum + 1
        fs.readFile(path, function(error, data)
        {   
            readingNum = readingNum - 1  
            onRead(error, data)
            if(waitQueue.length>0)  
            {
                var next = waitQueue.splice(0,1)[0]
                readFileInOrder(next.path, next.onRead)     
            }
            console.log('readFileInOrder readingNum:', readingNum)
        })
    }
    else
    {
        waitQueue[waitQueue.length] = {path:path, onRead:onRead}
    }

}



// 逻辑符号  正则没有对本身的逻辑运算符
// !!表示取反 
// &&表示并且 
// ||表示或者
// ((  xxxxx  )) 内容块  
// !! && ||属于同级
isMatch_regexp = function(regexpStr, targetStr)
{   
    //匹配最外层的括号内内容
    //parenthesesStr  第一个匹配到的括号内内容 带括号的 
    //如果没有匹配到则将参数字符串返回
    //特别的如果parenthesesRightStr前面有！！需要并入
    function getFirstParenthesesStr(regexpStr)
    {
        var parenthesesStr
        var parenthesesLeftStr
        var parenthesesRightStr

        var searchStartIdx = regexpStr.search(/\(\(/)
        if( searchStartIdx >=0 )
        {   
            var regexpStrOther = regexpStr.substr(searchStartIdx+2)
            var searchEndIdx = searchStartIdx  //searchStartIdx searchEndIdx 间是一段包括括号的 字符串
 
            for(var count=1;count>0;)
            {
                var searchStart1 = regexpStrOther.search(/\(\(/)
                var searchStart2 = regexpStrOther.search(/\)\)/)
                if(searchStart1<searchStart2)
                {
                    count=count+1
                    regexpStrOther = regexpStrOther.substr(searchStart1+2)
                    searchEndIdx = searchEndIdx + searchStart1+2
                }
                else
                {
                    count=count-1
                    regexpStrOther = regexpStrOther.substr(searchStart2+2)
                    searchEndIdx = searchEndIdx + searchStart2+2
                }
            }

            parenthesesRightStr = regexpStr.substr(searchEndIdx+2)
            if(searchStartIdx>=2&&regexpStr.substr(searchStartIdx-2,2) == '!!')
            {
                parenthesesLeftStr = regexpStr.substr(0, searchStartIdx-2)
                parenthesesStr = regexpStr.substr(searchStartIdx-2, searchEndIdx-searchStartIdx+2)
            }
            else
            {
              parenthesesLeftStr = regexpStr.substr(0, searchStartIdx)
              parenthesesStr = regexpStr.substr(searchStartIdx, searchEndIdx-searchStartIdx+2)
            }
        }
        else
        {
            return regexpStr
        }
        //console.log('getFirstParenthesesStr:',parenthesesStr, parenthesesLeftStr, parenthesesRightStr)
        return [parenthesesStr, parenthesesLeftStr, parenthesesRightStr]
    }

    //匹配最后一个前面带 || &&  操作符的regexpStr 连带操作符一起返回 操作符跟在operatorRightStr上
    //如果没有匹配到则将参数字符串返回
    function getLastOperatorRightStr(regexpStr)
    {
        var operatorLefttStr
        var operatorRightStr

        var lastIndex1 = regexpStr.lastIndexOf('&&')
        var lastIndex2 = regexpStr.lastIndexOf('||')

        var lastIndex = lastIndex1>lastIndex2?lastIndex1:lastIndex2

        if(lastIndex>=0)
        {
            operatorLefttStr = regexpStr.substr(0, lastIndex)
            operatorRightStr = regexpStr.substr(lastIndex)
        }
        else
        {
            return regexpStr
        }

        return [operatorLefttStr, operatorRightStr]
    }


    var str = getFirstParenthesesStr(regexpStr)

    //console.log(str, regexpStr)
    if( str != regexpStr) //匹配到括号
    {
        var parenthesesStr = str[0]
        var parenthesesLeftStr = str[1]
        var parenthesesRightStr = str[2]

        var isMatch = true
        //console.log('1111:',parenthesesStr)
        if(parenthesesStr.substr(0,2) == '!!')
        {
           var parenthesesStr = parenthesesStr.substr(4,parenthesesStr.length-6)
           //console.log('22222:',parenthesesStr)

           isMatch = isMatch && !isMatch_regexp(parenthesesStr, targetStr)
        }
        else
        {   
           var parenthesesStr = parenthesesStr.substr(2,parenthesesStr.length-4)
           //console.log('33333:',parenthesesStr)
           isMatch = isMatch && isMatch_regexp(parenthesesStr, targetStr)
        }

        if(parenthesesLeftStr)
        {
            var operator = parenthesesLeftStr.substr(-2)
            if(operator=='||')
            {
                isMatch = isMatch ||  isMatch_regexp( parenthesesLeftStr.substr(0, parenthesesLeftStr.length-2), targetStr )
            }
            else if(operator=='&&')
            {
                isMatch = isMatch &&  isMatch_regexp( parenthesesLeftStr.substr(0, parenthesesLeftStr.length-2), targetStr )
            }
        }

        if(parenthesesRightStr)
        {
            var operator = parenthesesRightStr.substr(0,2)
            //console.log('4444',parenthesesRightStr)
            if(operator=='||')
            {
                var parenthesesRightStr = parenthesesRightStr.substr(2)
                //console.log('5555',parenthesesRightStr)

                isMatch = isMatch ||  isMatch_regexp( parenthesesRightStr, targetStr )
            }
            else if(operator=='&&')
            { 
                var parenthesesRightStr = parenthesesRightStr.substr(2)
                isMatch = isMatch &&  isMatch_regexp( parenthesesRightStr, targetStr )
            }
        }

        return isMatch
    }
    else //没有括号
    {   
        var str = getLastOperatorRightStr(regexpStr)
        if(str != regexpStr)
        {   
            var operatorLefttStr = str[0]
            var operator = str[1].substr(0,2)
            var operatorRightStr = str[1].substr(2)

            if(operator == '||')
            {
                return isMatch_regexp(operatorLefttStr, targetStr) || isMatch_regexp(operatorRightStr, targetStr)

            }
            else if(operator == '&&')
            {
                return isMatch_regexp(operatorLefttStr, targetStr) && isMatch_regexp(operatorRightStr, targetStr)
            }
        }
        else //没有匹配碰到的第一个前面带 || &&  操作符的regexpStr
        {
            if(str.substr(0,2) == '!!')
                return !targetStr.match( new RegExp(str.substr(2)) ) 
            else
                return targetStr.match( new RegExp(str) )
        }
    }

}